<?php
  class Bean {
    public $model;
    private $storage = array();
    public function __construct($model) {
      if (!isset($model)) {
        throw new Exception('no model given');
        return;
      }
      $this->model = $model;
    }

    public function getId() {
      $key = $this->model->main_key;
      return $this->get($key);
    }

    public function setId($id) {
      $key = $this->model->main_key;
      $this->set($key, $id);
      return $this;
    }

    public function import($arr = array(), $keep_naming_style = false) {
      /*
        $arr: $key => $value
        (
          id => 12345,
          merchant_name => 'v-cafe'
        )

        $schemas: $_key => $schema
        (
          MerchantName => (
            'as' => 'merchant_name',
            'type' => 'string'
          )
        )
      */
      if ($keep_naming_style) {
        foreach ($arr as $key => $value) {
          if ($key == $this->model->main_key) {
            $this->setId($value);
            continue;
          }
          foreach ($this->model->schemas as $_key => $schema) {
            if ($_key == $key) {
              $this->set($key, $value);
              break;
            }
          }
        }
      } else {
        foreach ($arr as $key => $value) {
          if ($key == $this->model->main_key_as) {
            $this->setId($value);
            continue;
          }
          foreach ($this->model->schemas as $_key => $schema) {
            if (isset($schema['as'])) {
              $as = $schema['as'];
            } else {
              $as = $_key;
            }
            if ($as === $key) {
              $this->set($_key, $value);
              break;
            }
          }
        }
      }
      foreach ($this->model->schemas as $key => $schema) {
        if ($this->get($key) == null) {
          continue;
        }
        if ($schema['type'] == 'int') {
          $this->set($key, (int)$this->get($key));
        } else if ($schema['type'] == 'float') {
          $this->set($key, (float)$this->get($key));
        } else if ($schema['type'] == 'json') {
          $this->set($key, json_decode($this->get($key)));
        }
      }
      return $this;
    }
    
    public function export($remove_empty_string = true) {
      $result = array();
      foreach ($this->storage as $key => $value) {
        foreach ($this->model->schemas as $_key => $schema) {
          if ($_key == $key) {
            if (isset($schema['as'])) {
              $as = $schema['as'];
            } else {
              $as = $_key;
            }
            $result[$as] = $value;
            break;
          }
        }
      }
      if ($this->getId() != 0) {
        $result[$this->model->main_key_as] = $this->getId();
      }
      $result = $this->model->onExport($result);
      if ($remove_empty_string) {
        foreach ($result as $key => $value) {
          if ($value === '') {
            unset($result[$key]);
          }
        }
      }
      return $result;
    }

    public function set($key, $value) {
      $this->storage[$key] = $value;
      return $this;
    }

    public function setIfEmpty($key, $value) {
      if ($this->get($key) == null) {
        $this->set($key, $value);
      }
      return $this;
    }

    public function get($key) {
      if (isset($this->storage[$key])) {
        return $this->storage[$key];
      } else {
        return null;
      }
    }

    public function rm($key) {
      unset($this->storage[$key]);
      return $this;
    }

    public function save() {
      return $this->model->save($this);
    }

    public function trash() {
      return $this->model->trash($this);
    }

    public function clear() {
      $this->storage = array();
      $this->setId(0);
    }

    public function getAssociations($name) {
      return $this->model->getAssociations($this, $name);
    }

    public function associateWith($name, $value) {
      $this->model->associateWith($this, $name, $value);
      return $this;
    }

    public function disassociateWith($name, $value) {
      $this->model->disassociateWith($this, $name, $value);
      return $this;
    }
  }
?>
